let _toString = Object.prototype.toString

const map = {
  'number': 'Number',
  'boolean': 'Boolean',
  'null': 'Null',
  'undefined': 'Undefined',
  'symbol': 'Symbol',
  'string': 'String',
  'array': 'Array',
  'object': 'Object',
  'function': 'Function',
}

function getType(o) {
  return _toString.call(o).slice(8, -1)
}

function isTypeOf(o, type) {
  return map[type] && map[type] === getType(o)
}



function DFSClone(obj, visited = new Map()) {
  let _obj = {}
  if (isTypeOf(obj, 'array') || isTypeOf(obj, 'object')) {
    _obj = isTypeOf(obj, 'array') ? [] : {}
    if (visited.has(obj)) {
      _obj = visited.get(obj)
    } else {
      visited.set(obj)
      for (let key in obj) {
        _obj[key] = DFSClone(obj[key], visited)
      }
    }
  } else {
    return obj
  }
  return _obj
}

let a = {
  a: 1,
  b: {
    c: 'Test',
    d: null
  }
}
let bb = DFSClone(a)
console.log(bb);